package memory

import (
	"context"
	"errors"
	"sync"
	"time"

	"gitee.com/youkelike/session"
	cache "github.com/patrickmn/go-cache"
)

var (
	errKeyNotFound     = errors.New("session: key 不存在")
	errSessionNotFound = errors.New("session: 找不到 session")
)

// 内存中可以直接存储对象，结构可以是： id - session 对象
// store 中就存储了 id 和 session 对象之间的映射，
// session 对象中通过一个 map 来存储具体键值对
type Store struct {
	mutex sync.RWMutex
	// 这里缓存了所有用户的 session 对象
	sessions *cache.Cache

	expire time.Duration
}

// store 对象全局只需一个，可以做成单例
func NewStore(expire time.Duration) *Store {
	return &Store{
		sessions: cache.New(expire, time.Second),
		expire:   expire,
	}
}

func (s *Store) Generate(ctx context.Context, id string) (session.Session, error) {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	sess := &Session{
		id:   id,
		data: sync.Map{},
	}
	err := s.sessions.Add(id, sess, s.expire)
	return sess, err
}
func (s *Store) Get(ctx context.Context, id string) (session.Session, error) {
	s.mutex.RLock()
	defer s.mutex.RUnlock()

	sess, ok := s.sessions.Get(id)
	if !ok {
		return nil, errSessionNotFound
	}

	return sess.(*Session), nil
}
func (s *Store) Refresh(ctx context.Context, id string) error {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	// 这里不能用 store.Get 会形成死锁
	sess, ok := s.sessions.Get(id)
	if !ok {
		return errSessionNotFound
	}

	s.sessions.Set(id, sess, s.expire)
	return nil
}
func (s *Store) Remove(ctx context.Context, id string) error {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	s.sessions.Delete(id)
	return nil
}

type Session struct {
	id   string
	data sync.Map
}

func (s *Session) Get(ctx context.Context, key string) (any, error) {
	val, ok := s.data.Load(key)
	if !ok {
		return nil, errKeyNotFound
	}
	return val, nil
}
func (s *Session) Set(ctx context.Context, key string, val any) error {
	s.data.Store(key, val)
	return nil
}
func (s *Session) ID() string {
	return s.id
}
